const Joi = require('joi')
const { Op } = require('sequelize')
const R = require('@/models/Response')
const { Department } = require('@/models/model')
const { ERROR_USER_CODE, ERROR_SYSTEM_CODE } = require('@/constants/errorCode')
const {
  IS_INTEGER,
  IS_UNSAFE_INTEGER,
  IS_UNSAFE_INTEGER_2
} = require('@/constants/joiSchema')
const { SEPARATE_CHAR } = require('@/constants/index')
const { system } = require('@/config/system')
const { effect } = require('@/config/reactive')

const depSchema = {
  depIds: Joi.array().items(IS_UNSAFE_INTEGER),
  depId: IS_UNSAFE_INTEGER,
  page: IS_INTEGER.min(1).default(1),
  pageSize: IS_INTEGER.min(1).default(999),
  name: Joi.string().min(1).max(50),
  desc: Joi.string(),
  pid: IS_UNSAFE_INTEGER,
  sizeMax: IS_UNSAFE_INTEGER_2.min(0),
  cooperatDepIds: Joi.array().items(IS_UNSAFE_INTEGER)
}

const initDepSchema = () => {
  depSchema.sizeMax = IS_UNSAFE_INTEGER_2.min(0).max(Number(system.depSizeMax))
}
effect(initDepSchema)

const dumpCheck = {
  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证部门ID的合法性
   * @param {array<string>} depIds 部门ID数组
   * @param {boolean} ingoreRootId 是否忽略-1根部门ID
   */
  checkDepPids: async (depIds, ingoreRootId = false) => {
    let newdepIds = [...new Set(depIds)]
    // 不能出现重复的
    if (newdepIds.length !== depIds.length) {
      return false
    }
    // 将-1的筛选出来
    if (ingoreRootId) {
      newdepIds = newdepIds.filter((item) => +item !== -1)
    }

    if (newdepIds.length === 0) {
      return true
    }
    newdepIds = newdepIds.map((item) => BigInt(item))

    // 查看不重复的和数据库的是否对的上
    const deps = await Department.findAll({
      where: {
        id: {
          [Op.in]: newdepIds
        }
      },
      attributes: ['id']
    })
    if (deps.length !== newdepIds.length) {
      return false
    }

    return true
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证协作部门的合法性
   * @param {array<string>} cooperatDepIds 协作部门ID数组
   */
  checkCooperatDepIds: async (cooperatDepIds) => {
    if (!cooperatDepIds.length) {
      return false
    }
    // 验证合作部门ID的合法性
    if (cooperatDepIds.length === 1 && BigInt(cooperatDepIds[0]) === -1n) {
      // 代表协作部门为所有部门
      return true
    }

    if (cooperatDepIds.length === 1 && BigInt(cooperatDepIds[0]) === 0n) {
      // 代表协作部门为当前部门及其子部门
      return true
    }

    // 到这里，说明传递的是其他部门的ID，进行合法性校验,这里里面如果传递-1或者0不会过滤掉，认为参数不合法
    return await dumpCheck.checkDepPids(cooperatDepIds, false)
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证部门名称是否重复
   * @param {string} depName 部门名称
   */
  checkDepName: async (depName) => {
    const dep = await Department.findOne({
      where: {
        name: depName
      }
    })
    if (dep) {
      return false
    }
    return true
  }
}

/**
 * @description 部门列表查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: depSchema.page,
    pageSize: depSchema.pageSize,
    name: depSchema.name,
    pid: depSchema.pid
  }).validate(ctx.query)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  // const { pid } = ctx.query
  // // 验证父级部门ID是否正确,其实这里没有必要，如果非法，就查询不出
  // if (pid) {
  //   const b = await dumpCheck.checkDepPids([pid])
  //   if (!b) {
  //     ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
  //     return
  //   }
  // }
  ctx.query = schema.value
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建和更新部门时的验证
 * @param {*} ctx koa上下文
 * @param {*} depId 部门ID
 * @param {*} depName 部门名称
 * @param {*} pid 父部门ID
 * @param {*} cooperatDepIds 协作部门ID数组
 * @param {*} sizeMax 部门容量
 */
const addAndUpdCheck = async (
  ctx,
  depId,
  depName,
  pid,
  cooperatDepIds,
  sizeMax
) => {
  // 验证depId的合法性
  if (depId !== null) {
    const b4 = await dumpCheck.checkDepPids([depId], false)
    if (!b4) {
      ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
      return false
    }
  }

  // 验证部门名称的合法性
  if (depName !== null && depId === null) {
    const b3 = await dumpCheck.checkDepName(depName)
    if (!b3) {
      ctx.body = R.error(ERROR_USER_CODE.DEP_NAME_ERROR)
      return false
    }
  }

  // 验证pid的合法性
  if (pid !== null) {
    const b = await dumpCheck.checkDepPids([pid])
    if (!b) {
      ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
      return false
    }
  }

  // 验证协作部门ID的合法性
  if (cooperatDepIds !== null) {
    const b2 = await dumpCheck.checkCooperatDepIds(cooperatDepIds)
    if (!b2) {
      ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
      return false
    }
  }

  // TODO验证sizeMax的合法性
  if (sizeMax !== null) {
    return true
  }

  return true
}

/**
 * @description 创建部门时的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.createDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    name: depSchema.name.required(),
    pid: depSchema.pid.required(),
    sizeMax: depSchema.sizeMax.required(),
    cooperatDepIds: depSchema.cooperatDepIds.required(),
    desc: depSchema.desc
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { pid, name, cooperatDepIds } = ctx.request.body

  // 验证部门相关信息的合法性
  const b = await addAndUpdCheck(ctx, null, name, pid, cooperatDepIds, null)
  if (!b) {
    return
  }
  // 到这里说明参数没有问题,协作部门情况[0],[-1],[xxx,xxx]
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新部门时的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.updateDepValidate = async (ctx, next) => {
  const schema = Joi.object({
    depId: depSchema.depId.required(),
    name: depSchema.name.required(),
    desc: depSchema.desc,
    pid: depSchema.pid.required(),
    sizeMax: depSchema.sizeMax.required(),
    cooperatDepIds: depSchema.cooperatDepIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    console.log(schema.error)
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { depId, pid, name, cooperatDepIds } = ctx.request.body

  const b = await addAndUpdCheck(ctx, depId, name, pid, cooperatDepIds, null)
  if (!b) {
    return
  }

  // 验证pid对应的部门不是当前部门的后代部门，这样才可以进行修改
  // pid对应的部门也不能是自己本身
  const curDep = await Department.findByPk(BigInt(depId), {
    attributes: ['id', 'parentLevel']
  })
  const targetDep = await Department.findByPk(BigInt(pid), {
    attributes: ['id', 'parentLevel']
  })

  if (
    targetDep &&
    (targetDep.parentLevel.startsWith(
      curDep.parentLevel + SEPARATE_CHAR + curDep.id
    ) ||
      targetDep.id === curDep.id)
  ) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_PID_ERROR)
    return
  }

  // 到这里说明参数没有问题,协作部门情况[0],[-1],[xxx,xxx]
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量设置部门空间的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.setDepsSizeMaxValidate = async (ctx, next) => {
  const schema = Joi.object({
    depIds: depSchema.depIds.required(),
    sizeMax: depSchema.sizeMax.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { depIds } = ctx.request.body

  // 验证部门ID数组的合法性
  const b4 = await dumpCheck.checkDepPids(depIds, false)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 进行部门是否需要更新的必要检测
  // await Department.findByPk

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除部门接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delDepsValidate = async (ctx, next) => {
  const schema = Joi.object({
    depIds: depSchema.depIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { depIds } = ctx.request.body

  // 验证部门ID数组的合法性
  const b4 = await dumpCheck.checkDepPids(depIds, false)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  // 验证这些部门是否存在子部门，如果存在，不能删除
  const b5 = await Department.findOne({
    where: {
      pid: {
        [Op.in]: depIds.map((item) => BigInt(item))
      }
    }
  })

  if (b5) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_HAS_SUB_ERROR)
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 部门排序的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.sortDepsValidate = async (ctx, next) => {
  const schema = Joi.object({
    depIds: depSchema.depIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { depIds } = ctx.request.body

  // 验证部门ID数组的合法性
  const b4 = await dumpCheck.checkDepPids(depIds, false)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.DEP_ID_ERROR)
    return
  }

  await next()
}
